package cn.snmp.mutual.uk.stack;

import java.util.*;
import java.io.*;

public class SnmpContext extends AbstractSnmpContext implements SnmpContextFace, Cloneable {
    private static final String version_id = "@(#)$Id: SnmpContext.java,v 3.25 2009/03/05 12:51:29 birgita Exp $ Copyright Westhawk Ltd";
    String community;

    public SnmpContext(final String host, final int port) throws IOException {
        super(host, port);
        this.community = "public";
    }

    public SnmpContext(final String host, final int port, final String typeSocketA) throws IOException {
        super(host, port, typeSocketA);
        this.community = "public";
    }

    public SnmpContext(final String host, final int port, final String bindAddress, final String typeSocketA) throws IOException {
        super(host, port, bindAddress, typeSocketA);
        this.community = "public";
    }

    @Override
    public int getVersion() {
        return 0;
    }

    public String getCommunity() {
        return this.community;
    }

    public void setCommunity(final String newCommunity) {
        this.community = newCommunity;
    }

    @Override
    public byte[] encodePacket(final byte msg_type, final int rId, final int errstat, final int errind, final Enumeration ve, final Object obj) throws IOException, EncodingException {
        byte[] packet = null;
        if (this.isDestroyed) {
            throw new EncodingException("Context can no longer be used, since it is already destroyed");
        }
        final AsnEncoderv1 enc = new AsnEncoderv1();
        final ByteArrayOutputStream bay = enc.EncodeSNMP(this, msg_type, rId, errstat, errind, ve);
        final int sz = bay.size();
        if (sz > this.maxRecvSize) {
            throw new EncodingException("Packet size (" + sz + ") is > maximum size (" + this.maxRecvSize + ")");
        }
        packet = bay.toByteArray();
        return packet;
    }

    public byte[] encodePacket(final byte msg_type, final String enterprise, final byte[] IpAddress, final int generic_trap, final int specific_trap, final long timeTicks, final Enumeration ve) throws IOException, EncodingException {
        byte[] packet = null;
        final AsnEncoderv1 enc = new AsnEncoderv1();
        final ByteArrayOutputStream bay = enc.EncodeSNMP(this, msg_type, enterprise, IpAddress, generic_trap, specific_trap, timeTicks, ve);
        final int sz = bay.size();
        if (sz > this.maxRecvSize) {
            throw new EncodingException("Packet size (" + sz + ") is > maximum size (" + this.maxRecvSize + ")");
        }
        packet = bay.toByteArray();
        return packet;
    }

    @Override
    protected void processIncomingResponse(final ByteArrayInputStream in) throws DecodingException, IOException {
        final AsnDecoderv1 rpdu = new AsnDecoderv1();
        final AsnSequence seqPdu = rpdu.DecodeSNMP(in, this.getCommunity());
        if (seqPdu instanceof AsnPduSequence) {
            final AsnPduSequence pduSeq = (AsnPduSequence) seqPdu;
            if (pduSeq != null) {
                final Integer rid = new Integer(pduSeq.getReqId());
                final Pdu answ = this.getPdu(rid);
                if (answ != null) {
                    answ.fillin(pduSeq);
                } else if (AsnObject.debug > 3) {
                    System.out.println(this.getClass().getName() + ".processIncomingResponse(): No Pdu with reqid " + (int) rid);
                }
            } else if (AsnObject.debug > 3) {
                System.out.println(this.getClass().getName() + ".processIncomingResponse(): Error - missing seq input");
            }
        }
    }

    @Override
    public Pdu processIncomingPdu(final byte[] message) throws DecodingException, IOException {
        final AsnDecoderv1 rpdu = new AsnDecoderv1();
        final ByteArrayInputStream in = new ByteArrayInputStream(message);
        Pdu pdu = null;
        final AsnSequence seqPdu = rpdu.DecodeSNMP(in, this.getCommunity());
        if (seqPdu instanceof AsnTrapPduv1Sequence) {
            final AsnTrapPduv1Sequence pduSeq = (AsnTrapPduv1Sequence) seqPdu;
            if (pduSeq != null) {
                final TrapPduv1 trapPdu = new TrapPduv1(this);
                trapPdu.fillin(pduSeq);
                pdu = trapPdu;
            }
        } else {
            final AsnPduSequence pduSeq2 = (AsnPduSequence) seqPdu;
            if (pduSeq2 != null) {
                final byte type = pduSeq2.getRespType();
                switch (type) {
                    case -96: {
                        pdu = new GetPdu(this);
                        break;
                    }
                    case -95: {
                        pdu = new GetNextPdu(this);
                        break;
                    }
                    case -93: {
                        pdu = new SetPdu(this);
                        break;
                    }
                    default: {
                        if (AsnObject.debug > 3) {
                            System.out.println(this.getClass().getName() + ".ProcessIncomingPdu(): PDU received with type " + pduSeq2.getRespTypeString() + ". Ignoring it.");
                            break;
                        }
                        break;
                    }
                }
                if (pdu != null) {
                    pdu.fillin(pduSeq2);
                }
            }
        }
        return pdu;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        SnmpContext clContext = null;
        try {
            clContext = new SnmpContext(this.hostname, this.hostPort, this.bindAddr, this.typeSocket);
            clContext.setCommunity(new String(this.community));
        } catch (IOException exc) {
            throw new CloneNotSupportedException("IOException " + exc.getMessage());
        }
        return clContext;
    }

    @Override
    public String getHashKey() {
        final String str = this.hostname + "_" + this.hostPort + "_" + this.bindAddr + "_" + this.typeSocket + "_" + this.community + "_v" + this.getVersion();
        return str;
    }

    @Override
    public String toString() {
        final StringBuffer buffer = new StringBuffer("SnmpContext[");
        buffer.append("host=").append(this.hostname);
        buffer.append(", port=").append(this.hostPort);
        buffer.append(", bindAddress=").append(this.bindAddr);
        buffer.append(", socketType=").append(this.typeSocket);
        buffer.append(", community=").append(this.community);
        /*buffer.append(", #trapListeners=").append(this.trapSupport.getListenerCount());
        buffer.append(", #pduListeners=").append(this.pduSupport.getListenerCount());*/
        buffer.append("]");
        return buffer.toString();
    }
}
